package com.fingard.dsp.bank.directbank.vbao03.trade.utils;

import org.dom4j.*;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class XmlUtils {


    // 缺省字符集
    public static final String DEFAULT_ENCODING = "UTF-8";

    /**
     * 私有构造函数，阻止非法调用构造函数
     */
    private XmlUtils() {
    }

    /**
     * @param root    根节点
     * @param message 消息报文
     * @return
     * @throws IOException
     */
    public static String createXML(String root, String endcoding,
                                   LinkedHashMap<String, String> message) throws IOException {

        // 获得document
        DocumentFactory factory = new DocumentFactory();
        Document document = factory.createDocument();

        // 根节点
        Element Root = document.addElement(root);
        // 遍历发送报文
        for (String key : message.keySet()) {
            String value = message.get(key);
            if (null == value || value.length() <= 0) {
                continue;
            } else {
                Element element = Root.addElement(key);
                element.addText(value);
            }
        }

        // 转换为xml字符串
        String mesXML = toXML(document, endcoding);
        // 排除空格、回车、换行、制表符
        mesXML = replace2Blank(replaceBlank(mesXML));

        return mesXML;
    }

    /**
     * 组装含有报文头和报文体的xml报文
     *
     * @param root    根节点
     * @param head    报文头
     * @param body    报文体
     * @param message 消息报文
     * @return
     * @throws IOException
     */
    public static String createXML2(String root, String head, String body,
                                    String endcoding, LinkedHashMap<String, String> message)
            throws IOException {

        // 获得document
        DocumentFactory factory = new DocumentFactory();
        Document document = factory.createDocument();

        // 根节点
        Element Root = document.addElement(root);
        Element Head = Root.addElement(head);
        Element Body = Root.addElement(body);

        // 遍历发送报文
        int flag = 0; //报文头和报文体拼接flag
        Element element = null;
        for (String key : message.keySet()) {
            String value = message.get(key);
            if (null == value || value.length() <= 0) {
                continue;
            }
            if (key.equals(head)) {
                flag = 1;
                continue;
            }
            switch (flag) {
                case 0:
                    element = Head.addElement(key);
                    element.addText(value);
                    break;
                case 1:
                    element = Body.addElement(key);
                    element.addText(value);
                    break;
                default:
                    break;
            }
        }

        // 转换为xml字符串
        String mesXML = toXML(document, endcoding);
        // 排除空格、回车、换行、制表符
        mesXML = replace2Blank(replaceBlank(mesXML));

        return mesXML;
    }

    /**
     * 把XML文档转化为String返回
     *
     * @param document 要转化的XML的Document
     * @param encoding 编码类型
     * @return <code>String</code>
     * @throws IOException
     */
    public static String toXML(Document document, String encoding)
            throws IOException {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        toXML(document, stream, encoding);
        if (stream != null) {
            try {
                stream.close();
            } catch (java.io.IOException ex) {
            }
        }
        return stream.toString();
    }

    /**
     * 把XML的Document转化 不支持给定Schema文件的校验
     *
     * @param document  XML文档
     * @param outStream 输出写入器
     * @param encoding  编码类型
     * @throws IOException
     */
    public static void toXML(Document document, OutputStream outStream,
                             String encoding) throws IOException {
        //
        OutputFormat outformat = OutputFormat.createPrettyPrint();
        if (encoding == null || encoding.trim().equals("")) {
            encoding = DEFAULT_ENCODING;
        }
        // 设置编码类型
        outformat.setEncoding(encoding);
        XMLWriter xmlWriter = null;
        try {
            xmlWriter = new XMLWriter(outStream, outformat);
            xmlWriter.write(document);
            xmlWriter.flush();
        } catch (java.io.IOException ex) {
            throw ex;
        } finally {
            if (xmlWriter != null) {
                try {
                    xmlWriter.close();
                } catch (java.io.IOException ex) {
                }
            }
        }
    }

    /**
     * 解析xml字符串
     *
     * @param source
     * @throws DocumentException
     */
    @SuppressWarnings("unchecked")
    public static Map<String, String> parseXML(String source)
            throws DocumentException {

        // 返回值
        Map<String, String> value = new HashMap<String, String>();
        // 转换为document
        Document document = DocumentHelper.parseText(source);
        // 取得根节点
        Element root = document.getRootElement();
        // 取得根节点下所有节点
        List<Element> list = root.elements();
        // 取得节点值
        for (Element e : list) {
            value.put(e.getName(), e.getText());
        }

        return value;
    }

    /**
     * 解析较复杂xml字符串
     *
     * @param source 原字符串
     * @param eList  要解析的element元素list
     * @param value  返回值初始化hashmap
     * @param flag   迭代标示
     * @throws DocumentException
     */
    @SuppressWarnings("unchecked")
    public static SortedMap<String, String> parseXML2(String source, List<Element> elList, SortedMap<String, String> value, boolean flag)
            throws DocumentException {

        // 返回值
        Element root = null;
        List<Element> list = null;
        if (flag) {
            // 转换为document
            Document document = DocumentHelper.parseText(source);
            // 取得根节点
            root = document.getRootElement();
            // 取得根节点下所有节点
            list = root.elements();
        } else {
            list = elList;
        }

        // 取得节点值
        for (Element el : list) {
            List<Element> listHead = el.elements();
            if (listHead.size() > 0) {
                parseXML2(null, listHead, value, false);
            } else {
                if (null != el.getText() && el.getText().length() > 00) {
                    value.put(el.getName(), el.getText());
                }
            }
        }

        return value;
    }


    /**
     * 去掉字符串中的换行、回车、制表符
     *
     * @param str
     * @return
     */
    public static String replaceBlank(String str) {
        String dest = "";
        if (str != null) {
            Pattern p = Pattern.compile("\\t|\\r|\\n");
            Matcher m = p.matcher(str);
            dest = m.replaceAll("");
        }
        return dest;
    }

    /**
     * 去掉字符串中连续出现两次的空格
     *
     * @param str
     * @return
     */
    public static String replace2Blank(String str) {
        String dest = "";
        if (str != null) {
            Pattern p = Pattern.compile("\\s{2}");
            Matcher m = p.matcher(str);
            dest = m.replaceAll("");
        }
        return dest;
    }

    public static SortedMap<String, String> String2SortedMapString(String content) throws DocumentException {
        return convert2SortedMapString(String2MapObject(content));
    }

    public static Map<String, Object> String2MapObject(String content) throws DocumentException {
        Document doc = DocumentHelper.parseText(content);
        return Dom2Map(doc);
    }

    @SuppressWarnings("unchecked")
    public static Map<String, Object> Dom2Map(Document doc) {
        Map<String, Object> map = new HashMap<String, Object>();
        if (doc == null) {
            return map;
        }
        Element root = doc.getRootElement();
        for (Iterator<Element> iterator = root.elementIterator(); iterator.hasNext(); ) {
            Element e = iterator.next();
            List<Element> list = e.elements();
            if (list.size() > 0) {
                map.put(e.getName(), Dom2Map(e));
            } else {
                map.put(e.getName(), e.getText());
            }
        }
        return map;
    }

    @SuppressWarnings("unchecked")
    public static Map<String, Object> Dom2Map(Element e) {
        Map<String, Object> map = new HashMap<String, Object>();
        List<Element> list = e.elements();
        if (list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                Element iter = (Element) list.get(i);
                List<Object> mapList = new ArrayList<Object>();

                if (iter.elements().size() > 0) {
                    Map<String, Object> m = Dom2Map(iter);
                    if (map.get(iter.getName()) != null) {
                        Object obj = map.get(iter.getName());
                        if (!obj.getClass().getName().equals("java.util.ArrayList")) {
                            mapList = new ArrayList<Object>();
                            mapList.add(obj);
                            mapList.add(m);
                        }
                        if (obj.getClass().getName().equals("java.util.ArrayList")) {
                            mapList = (List<Object>) obj;
                            mapList.add(m);
                        }
                        map.put(iter.getName(), mapList);
                    } else {
                        map.put(iter.getName(), m);
                    }
                } else {
                    if (map.get(iter.getName()) != null) {
                        Object obj = map.get(iter.getName());
                        if (!obj.getClass().getName().equals("java.util.ArrayList")) {
                            mapList = new ArrayList<Object>();
                            mapList.add(obj);
                            mapList.add(iter.getText());
                        }
                        if (obj.getClass().getName().equals("java.util.ArrayList")) {
                            mapList = (List<Object>) obj;
                            mapList.add(iter.getText());
                        }
                        map.put(iter.getName(), mapList);
                    } else {
                        map.put(iter.getName(), iter.getText());
                    }
                }
            }
        } else {
            map.put(e.getName(), e.getText());
        }
        return map;
    }

    public static SortedMap<String, String> convert2SortedMapString(Map<String, Object> map) {
        SortedMap<String, String> result = new TreeMap<String, String>();

        if (map != null) {
            String key = "";
            String val = "";
            for (Iterator<String> itr = map.keySet().iterator(); itr.hasNext(); ) {
                key = itr.next();
                Object obj = map.get(key);
                if (obj != null) {
                    val = obj.toString();
                } else {
                    val = null;
                }
                result.put(key, val);
            }
        }

        return result;
    }
}
